package redishelper

import (
	"encoding/json"
	"fmt"
	"github.com/gomodule/redigo/redis"
	"github.com/mjiulee/go-sessions"
	sess_redis "github.com/mjiulee/go-sessions/sessiondb/redis"
	"github.com/mjiulee/go-sessions/sessiondb/redis/service"
	"github.com/mjiulee/lego"
	"github.com/mjiulee/lego/toolbox"
	"saas_sys_base/sysconfig"
	"sync"
	"time"
)

const ()

var _pool *redis.Pool
var once sync.Once

type RedisHelper struct {
}

func init() {
	//s2 := sessions.New(sessions.Config{Cookie: "sessionscookieid"})
	//GetRedisConn()
}

/* 获取Redis连接
* params:
  ---
*/
func GetRedisConn() (redis.Conn, error) {
	if _pool == nil {
		once.Do(func() {
			host := sysconfig.Config.Redis.Redis_Host
			port := sysconfig.Config.Redis.Redis_Port
			password := sysconfig.Config.Redis.Redis_Pswd


			pool_size := 30 //TODO 增大这个值看看，redis最大延迟会不会缩短
			_pool = redis.NewPool(func() (redis.Conn, error) {
				conn, err := redis.Dial("tcp", fmt.Sprintf("%s:%s", host, port), redis.DialPassword(password))
				if err != nil {
					return nil, err
				}
				return conn, nil
			}, pool_size)

			//
			db := sess_redis.New(service.Config{Network: service.DefaultRedisNetwork,
				Addr:        fmt.Sprintf("%s:%s", host, port),
				Password:    password,
				Database:    "",
				MaxIdle:     0,
				MaxActive:   0,
				IdleTimeout: time.Duration(60) * time.Minute,
				Prefix:      "admin_session_",
			})
			sessions.UseDatabase(db)
		})
	}
	return _pool.Get(), nil
}

/*
封装一层，直接操作对象 start
*/

func RedisGetKeyEx(key string, val interface{}) error {
	valStr, err := RedisGetKey(key)
	if err != nil && err != redis.ErrNil {  //此错误ErrNil不需要打印: redigo: nil returned
		lego.LogError(err)
	}

	err = json.Unmarshal([]byte(valStr), val)
	return err
}

func RedisSetKeyEx(key string, val interface{}) error {
	valByte, err := json.Marshal(val)
	if err != nil {
		return err
	}

	_, err = RedisSetKey(key, string(valByte), "0", false)
	if err != nil && err != redis.ErrNil {  //此错误不需要打印: redigo: nil returned
		lego.LogError(err)
	}
	return err
}

func RedisGetKeyEx2(ctxExt *lego.RequestCtxExtent, key string, val interface{}) error {

	ts0 := toolbox.InsertStartTime(lego.GetTsGroupInContext(ctxExt), "RedisGetKeyEx2 call RedisGetKey")

	valStr, err := RedisGetKey(key)
	if err != nil {
		return err
	}

	toolbox.InsertEndTime(ts0)

	ts1 := toolbox.InsertStartTime(lego.GetTsGroupInContext(ctxExt), "RedisGetKeyEx2 call Unmarshal")
	err = json.Unmarshal([]byte(valStr), val)
	toolbox.InsertEndTime(ts1)
	return err
}

/*

封装一层，直接操作对象 end

*/

/*
 * 再多封装一次，get、set的用法.
 */
func RedisGetKey(key string) (string, error) {
	redisconn, err := GetRedisConn()
	if err != nil {
		return "", err
	}
	defer redisconn.Close()
	return redis.String(redisconn.Do("GET", key))
}

func RedisDelKey(key string) error {
	redisconn, err := GetRedisConn()
	if err != nil {
		return err
	}
	defer redisconn.Close()
	_, err = redisconn.Do("DEL", key)
	return err
}

/*
 * 再多封装一次，get、set的用法.
 */
func RedisSetKey(key, value, expiretime string, ifexpire bool) (string, error) {
	redisconn, err := GetRedisConn()
	if err != nil {
		return "", err
	}
	defer redisconn.Close()

	if ifexpire {
		return redis.String(redisconn.Do("SET", key, value, "EX", expiretime))
	} else {
		return redis.String(redisconn.Do("SET", key, value))
	}
}

/* 使用例子：
	c := GetRedisConn.Get()

    //记得销毁本次链连接
    defer c.Close()

    //写入数据
    _, err := c.Do("SET", "go_key", "redigo")
    if err != nil {
        logger.Runtime().Info(map[string]interface{}{"error": err}, "error while setting")
    }

    //判断key是否存在
    is_key_exit, err := redis.Bool(c.Do("EXISTS", "go_key"))
    if err != nil {
        logger.Runtime().Info(map[string]interface{}{"error": err}, "error while existing")
    }

    //获取value并转成字符串
    account_balance, err := redis.String(c.Do("GET", "go_key"))
    if err != nil {
        logger.Runtime().Info(map[string]interface{}{"error": err}, "error while getting")
    }

    //删除key
    _, err = c.Do("DEL", "go_key")
    if err != nil {
        logger.Runtime().Info(map[string]interface{}{"error": err}, "error while deleting")
    }

    //设置key过期时间
    _, err = c.Do("SET", "mykey", "superWang", "EX", "5")
    if err != nil {
        fmt.Println("redis set failed:", err)
    }

    //创建key时设置5s过期
    _, err := c.Do("SET", "go_key:ex", "redigo", "EX", 5)
    if err != nil {
        logger.Runtime().Info(map[string]interface{}{"error": err}, "error while setting")
    }

    //对已有key设置5s过期时间
    n, err := c.Do("EXPIRE", "go_key", 5)
    if err != nil {
        logger.Runtime().Info(map[string]interface{}{"error": err}, "error while setting")
    } else if n != int64(1) {
        fmt.Println("failed")
    }

	// 列表
	c.Do("lpush", "redlist", "qqq")
	c.Do("lpush", "redlist", "www")
	c.Do("lpush", "redlist", "eee")

	// 遍历
	values, _ := redis.Values(c.Do("lrange", "redlist", "0", "100"))
 	for _, v := range values {
 	    fmt.Println(string(v.([]byte)))
 	}
 	// 或者
 	var v1 string
 	redis.Scan(values, &v1)
	fmt.Println(v1)

*/

/*func RedisGet(key string) {
	//opt := go_redis.Options{}
	opt, _ := go_redis.ParseURL("")
	redisCli := go_redis.NewClient(opt)
	_, _ = redisCli.Get(key).Result()
}*/
